package com.cls.business.service.impl;

import com.cls.business.entity.*;
import com.cls.business.mapper.DeclareTopicMapper;
import com.cls.business.mapper.TopicPlanMapper;
import com.cls.business.service.IReviewService;
import com.cls.business.service.ITopicSubjectService;
import com.cls.business.vo.ExpertCondition;
import com.cls.common.enums.DictEnum;
import com.cls.common.service.CreateRedisKey;
import com.cls.common.service.RedisService;
import com.cls.system.entity.Configure;
import com.cls.system.entity.Expert;
import com.cls.system.mapper.ConfigureMapper;
import com.cls.system.service.IExpertService;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

@Service
@RequiredArgsConstructor
public class ExpertAllocationService {

    private final static Logger LOG = LoggerFactory.getLogger(ExpertAllocationService.class);

    @Autowired
    private IExpertService expertService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private ITopicSubjectService topicSubjectService;

    @Autowired
    private DeclareTopicMapper declareTopicMapper;

    @Autowired
    private IReviewService reviewService;

    @Autowired
    private TopicPlanMapper topicPlanMapper;

    @Autowired
    private ConfigureMapper configureMapper;

    private List<ExpertGroup> groups;

    private ReentrantLock lock = new ReentrantLock();


    /**
     * 根据提供各类专家数获取专家分组信息
     */
    public void autoAssignExpert(Long planId, List<ITopic> topics){
        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        int perWorkload = 20;
        TopicPlan plan = topicPlanMapper.selectById(planId);
        if(plan == null){
            LOG.error("未找到期次！");
            return;
        }
        Configure configure = configureMapper.selectById(plan.getConfigureId());
        if(configure != null){
            perWorkload = configure.getWorkload();
        }
        // 初始化数据，清理缓存
        restoreExpertBankCache(perWorkload);
        groups = new ArrayList();
        for(ITopic topic:topics){
            TopicSubject topicSubjectQuery =new TopicSubject();
            topicSubjectQuery.setTopicId(topic.getTopicId());
            List<TopicSubject> topicSubjects = topicSubjectService.findTopicSubjects(topicSubjectQuery);
            topic.setTopicSubjects(topicSubjects);
        }
        assignExpert(topics, configure);
        reviewService.createReviewData(groups);
        groups.clear();
    }

    /**
     * 对专家进行按类别进行分组管理，并缓存进redis
     * 先删除之前缓存的相关数据
     */

    public void restoreExpertBankCache(int perWorkload){
        List<String> expertClassifyKeys = redisService.scan(CreateRedisKey.getAllExpertClassifyKeys() + "*");
        List<String> expertClassifyWorkloadKeys = redisService.scan(CreateRedisKey.getAllExpertClassifyWorkloadKeys() + "*");
        expertClassifyKeys.addAll(expertClassifyWorkloadKeys);
        List<String> expertKeys = redisService.scan(CreateRedisKey.getAllExpertIDKeys() + "*");
        expertClassifyKeys.addAll(expertKeys);
        redisService.delAll(expertClassifyKeys); // 清空缓存
        Expert param = new Expert();
        param.setIsPublish(true);
        List<Expert> experts = expertService.findExperts(param);
        for (Expert one : experts) {
            one.setWorkload(perWorkload);
            redisService.sSet(CreateRedisKey.getExpertClassifyKey(one, false), one.getExpertId() + "");
            redisService.set(CreateRedisKey.createExpertIDKeys(one.getExpertId() + ""), one);
        }
    }




    private boolean assignExpert(List<ITopic> topics, Configure configure){
        if(topics == null || configure == null){
            LOG.error("课题列表为空或条件为null！");
            return false;
        }
        int perWorkload = configure.getWorkload();
        for(ITopic topic:topics){
            HashMap<String, Object> param = new HashMap();
            param.put("topicId", topic.getTopicId());
            String status;
            if(topic instanceof Topic){
                status = DictEnum.CHECK_PASSED.getCode();
            } else {
                status = DictEnum.CONCLUDE_ASSIGN.getCode();

            }

            List<DeclareTopic> declareTopics = declareTopicMapper.selectByStatusAndTopicId(status, topic.getTopicId(), topic.getPlanId());
            if(declareTopics == null || declareTopics.size() < 1){
                LOG.error("该课题没有关联的申报信息！");
                continue;
            }
            int groupNum = declareTopics.size()/ perWorkload;
            int numOfLastGroup = declareTopics.size() % perWorkload;
            List<TopicSubject> topicSubjects = topic.getTopicSubjects();

            // 计算每组专家类型的分配
            List<String> expertTypes = calcExpertTypes(topicSubjects);
            if(expertTypes == null){
                LOG.error("专家组个数计算失败！");
                continue;
            }
            if(groupNum > 0){ // 第一种情况，这组专家的工作量需要饱和
                for(int i = 0; i < groupNum; i++ ){
                    calcAndClassifyExperts(topic, expertTypes, declareTopics, i, expertTypes.size(), configure);
                }
            }
            if(numOfLastGroup > 0){
                calcAndClassifyExperts(topic, expertTypes, declareTopics, groupNum, expertTypes.size(), configure);
            }
       }
        return true;
    }

    private List<String> calcExpertTypes(List<TopicSubject> topicSubjects){
        List<String> expertTypes = new ArrayList();
        for(TopicSubject one: topicSubjects){
            for(int i = 0; i < one.getSubjectNum(); i++){
                expertTypes.add(one.getSubjectTypeCode());
            }
        }
        return expertTypes;
    }


    private boolean calcAndClassifyExperts(ITopic topic, List<String> expertTypes, List<DeclareTopic> declareTopics, int groupNum, int expertNum, Configure configure){
        if(declareTopics == null || declareTopics.size() < 1 || configure == null){
            return false;
        }

        int perWorkload = configure.getWorkload();
        int declareSize = declareTopics.size();
        int begin = groupNum * perWorkload;
        int end = (groupNum + 1) * perWorkload; // 不包含最好一个元素
        if(begin >= declareSize){ // 数组越界判断
            return false;
        }

        boolean usedAssign = false;
        if(declareSize < end){
            end = declareSize;
            usedAssign = true;
        }
        int workload = end - begin; //需要处理的个数

        List<Expert> selectedExperts = getExpertFromCache(expertTypes, workload, usedAssign, configure);
        boolean exist = false;
        if(selectedExperts != null && selectedExperts.size() == expertNum){
            exist = true;
        }

        for(int i = 0; i < expertNum; i ++){ // 生成ExpertGroup 和 Review
            ExpertGroup expertGroup = new ExpertGroup();
            List<Review> reviews = new ArrayList<>();
            expertGroup.setReviews(reviews);
            expertGroup.setPlanId(topic.getPlanId());
            expertGroup.setTopicId(topic.getTopicId());
            expertGroup.setGroupNo(groupNum + 1);

            if(exist) {
                Expert one = selectedExperts.get(i);

                int afterWorkload = one.getWorkload() - workload;
                if (afterWorkload > 0) { // 工作量存在结余的专家
                    one.setWorkload(afterWorkload);
                    if (!one.isUsedAssign()) {
                        redisService.sSet(CreateRedisKey.getExpertClassifyKey(one, true), one.getExpertId() + "");
                        redisService.setRemove(CreateRedisKey.getExpertClassifyKey(one, false), one.getExpertId() + "");
                    } else {
                        redisService.sSet(CreateRedisKey.getExpertClassifyKey(one, true), one.getExpertId() + "");
                    }
                    redisService.set(CreateRedisKey.createExpertIDKeys(one.getExpertId() + ""), one);
                } else if (afterWorkload == 0) {
                    one.setWorkload(afterWorkload);
                    if (!one.isUsedAssign()) {
                        redisService.setRemove(CreateRedisKey.getExpertClassifyKey(one, false), one.getExpertId() + "");
                    } else {
                        redisService.setRemove(CreateRedisKey.getExpertClassifyKey(one, true), one.getExpertId() + "");
                    }
                    redisService.set(CreateRedisKey.createExpertIDKeys(one.getExpertId() + ""), one);
                } else {
                    LOG.error("数据异常！");
                }
                expertGroup.setExpertId(one.getExpertId());
            }
            groups.add(expertGroup);
            for(int j = begin; j < end; j++){
                DeclareTopic declareTopic = declareTopics.get(j);
                Review review = new Review();
                review.setPlanId(topic.getPlanId());
                review.setDeclareId(declareTopic.getDeclareId());
                review.setGroupId(expertGroup.getExpertGroupId());
                review.setIsSubmit(false);
                if(exist){
                    review.setExpertId(selectedExperts.get(i).getExpertId());
                }
                reviews.add(review);
            }
        }
        return true;
    }

    /**
     * 从未分配的缓存中获取专家,优先满足一个实务专家,同一组专家所在单位不同，其次再区别京内与京外专家
     * @param expertTypes
     * @return
     */
    private List<Expert> getExpertFromCache(List<String> expertTypes, int workload, boolean usedAssign, Configure configure){
        if(expertTypes == null || expertTypes.size() < 1 || workload < 1) {
            LOG.error("getExpertFromCache method param error！");
            return null;
        }

        List<Expert> retExperts = new ArrayList();
        boolean operation = "1".equals(configure.getExpertSpecialCode()) ? true : false;
        boolean capital = "0".equals(configure.getExpertSpecialCode()) ? true : false;
        for(int i = 0; i < expertTypes.size(); i++){
            ExpertCondition condition = new ExpertCondition();
            condition.setExperts(retExperts);
            condition.setSubjectType(expertTypes.get(i));
            condition.setWorkload(workload);
            condition.setPriorityOperation(operation);
            condition.setPriorityCapital(capital);
            if(operation == true){
                condition.setPriorityOperation(false);
                //priorityOperation = false;
            }
            if(capital == true){
                condition.setPriorityCapital(false);
                //priorityCapital = false;
            }
            Expert expert;
            if(usedAssign){
                condition.setUsedCache(true);
                expert = getExpertBySubjectTypeAndWorkload(condition);
                if(expert != null){
                    retExperts.add(expert);
                } else {
                    condition.setUsedCache(false);
                    expert = getExpertBySubjectTypeAndWorkload(condition);
                    if (expert != null) {
                        retExperts.add(expert);
                    }
                }
            } else {
                condition.setUsedCache(false);
                expert = getExpertBySubjectTypeAndWorkload(condition);
                if(expert != null){
                    retExperts.add(expert);
                }
            }
            if(expert == null){
                // 解除锁定
                for(Expert one:retExperts){
                    if(one.getWorkload() < configure.getWorkload()){ // 来自于已用缓存
                        redisService.sSet(CreateRedisKey.getExpertClassifyKey(one, true), one.getExpertId() + "");
                    } else {
                        redisService.sSet(CreateRedisKey.getExpertClassifyKey(one, false), one.getExpertId() + "");
                    }
                }
                LOG.error("未找到满足条件的专家组！");
                return null;
            } else {
                // 锁定专家
                if(expert.getWorkload() < configure.getWorkload()){
                    redisService.setRemove(CreateRedisKey.getExpertClassifyKey(expert, true), expert.getExpertId() + "");
                } else {
                    redisService.setRemove(CreateRedisKey.getExpertClassifyKey(expert, false), expert.getExpertId() + "");
                }
            }

            // 分析Key的特性
            if(!operation && CreateRedisKey.OPERATION_EXPERT_TYPE.equals(expert.getFeatureTypeCode())){
                operation = true;
            }
            if(!capital && CreateRedisKey.CAPITAL_EXPERT_TYPE.equals(expert.getDistrictTypeCode())){
                capital = true;
            }
        }
        return retExperts;
    }

    /**
     * 通过key获取专家信息，同一组专家所在单位应不同
     * @param key
     * @param selectedExperts
     * @return
     */
    private boolean getExpertByKey(String key, List<Expert> selectedExperts){
        List<Expert> diffCompanyExperts = new ArrayList();
        // 将同一单位的专家排除后，再随机获取一个专家
        Set<Object> expertIds = redisService.sGet(key);
        if(expertIds == null || expertIds.size() < 1){
            LOG.error("不存在该专家：" + key);
            return false;
        }
        for(Object one:expertIds){
            String expertId = (String)one;
            Expert expert = (Expert) redisService.get(CreateRedisKey.createExpertIDKeys(expertId));
            if(selectedExperts.size() > 0){
                boolean sameCompany = false;
                for(Expert retExpert:selectedExperts){
                    if(retExpert.getCompany().equals(expert.getCompany())){
                        sameCompany = true;
                        break;
                    }
                }
                if(!sameCompany){
                    diffCompanyExperts.add(expert);
                }
            } else {
                diffCompanyExperts.add(expert);
            }
        }
        if(diffCompanyExperts.size() < 1){
            LOG.error("专家可能在同一单位！");
            return false;
        }
        Random random = new Random();
        int n = random.nextInt(diffCompanyExperts.size());
        selectedExperts.add(diffCompanyExperts.get(n));
        return true;
    }



    /**
     * 从未分配的缓存中获取专家,优先满足一个实务专家,同一组专家所在单位不同，其次再区别京内与京外专家
     * @param topicSubjects
     * @return
     */
//    private List<Expert> getExpertFromUnallocatedCache(List<TopicSubject> topicSubjects){
//        if(topicSubjects == null) {
//            LOG.error("getExpertFromUnallocatedCache method param error！");
//            return null;
//        }
//
//        List<String> subjects = new ArrayList();
//        for(TopicSubject one: topicSubjects){
//            for(int i = 0; i < one.getNum(); i++){
//                subjects.add(one.getSubjectTypeCode());
//            }
//        }
//
//        List<Expert> retExperts = new ArrayList();
//        boolean operation = false;
//        String lastDistrictType = null;
//        for(int i = 0; i < subjects.size(); i++){
//            String key = null;
//            long num = 0;
//            if(operation == false) {
//                operation = true;
//                key = CreateRedisKey.getOperationAndCapitalKey(subjects.get(i), false);
//                num = redisService.sGetSetSize(key);
//                if(num == 0) {
//                    key = CreateRedisKey.getOperationAndOutCapitalKey(subjects.get(i), false);
//                    num = redisService.sGetSetSize(key);
//                }
//                if(num == 0) {
//                    operation = false;
//                    key = CreateRedisKey.getTheoryAndCapitalKey(subjects.get(i), false);
//                    num = redisService.sGetSetSize(key);
//                }
//                if(num == 0) {
//                    operation = false;
//                    key = CreateRedisKey.getTheoryAndCapitalKey(subjects.get(i), false);
//                    num = redisService.sGetSetSize(key);
//                }
//                if(num == 0) {
//                    key = null;
//                    return null;
//                }
//            } else {
//                if(CreateRedisKey.CAPITAL_EXPERT_TYPE.equals(lastDistrictType)){
//                    key = CreateRedisKey.getTheoryAndOutCapitalKey(subjects.get(i), false);
//                    num = redisService.sGetSetSize(key);
//                    if(num == 0) {
//                        key = CreateRedisKey.getTheoryAndCapitalKey(subjects.get(i), false);
//                        num = redisService.sGetSetSize(key);
//                    }
//                    if(num == 0) {
//                        key = null;
//                        return null;
//                    }
//                } else {
//                    key = CreateRedisKey.getTheoryAndCapitalKey(subjects.get(i), false);
//                    num = redisService.sGetSetSize(key);
//                    if(num == 0) {
//                        key = CreateRedisKey.getTheoryAndOutCapitalKey(subjects.get(i), false);
//                        num = redisService.sGetSetSize(key);
//                    }
//                    if(num == 0) {
//                        key = null;
//                        return null;
//                    }
//                }
//            }
//            getExpertByKey(key, retExperts);
//        }
//        return retExperts;
//    }

    /**
     * 1)从未分配的缓存中获取专家,优先满足一个实务专家,同一组专家所在单位不同，其次再区别京内与京外专家
     * 2) 根据operation与capital的取值优先进行查询判断
     * @param expertCondition
     * @return
     */
    private Expert getExpertBySubjectTypeAndWorkload(final ExpertCondition expertCondition){
        String key;
        Expert expert;
        if(expertCondition.isPriorityOperation() && expertCondition.isPriorityCapital()) {
            key = CreateRedisKey.getOperationAndCapitalKey(expertCondition.getSubjectType(), expertCondition.isUsedCache());
            expert = getExpertByCondition(key, expertCondition);
            if(expert != null){
                return expert;
            }
            key = CreateRedisKey.getOperationAndOutCapitalKey(expertCondition.getSubjectType(), expertCondition.isUsedCache());
            expert = getExpertByCondition(key, expertCondition);
            if(expert != null){
                return expert;
            }
            key = CreateRedisKey.getTheoryAndCapitalKey(expertCondition.getSubjectType(), expertCondition.isUsedCache());
            expert = getExpertByCondition(key, expertCondition);
            if(expert != null){
                return expert;
            }
            key = CreateRedisKey.getTheoryAndOutCapitalKey(expertCondition.getSubjectType(), expertCondition.isUsedCache());
            expert = getExpertByCondition(key, expertCondition);
            return expert;
        }else if(expertCondition.isPriorityOperation() && !expertCondition.isPriorityCapital()) {
            key = CreateRedisKey.getOperationAndOutCapitalKey(expertCondition.getSubjectType(), expertCondition.isUsedCache());
            expert = getExpertByCondition(key, expertCondition);
            if(expert != null){
                return expert;
            }
            key = CreateRedisKey.getOperationAndCapitalKey(expertCondition.getSubjectType(), expertCondition.isUsedCache());
            expert = getExpertByCondition(key, expertCondition);
            if(expert != null){
                return expert;
            }
            key = CreateRedisKey.getTheoryAndOutCapitalKey(expertCondition.getSubjectType(), expertCondition.isUsedCache());
            expert = getExpertByCondition(key, expertCondition);
            if(expert != null){
                return expert;
            }
            key = CreateRedisKey.getTheoryAndCapitalKey(expertCondition.getSubjectType(), expertCondition.isUsedCache());
            expert = getExpertByCondition(key, expertCondition);
            return expert;
        }else if(!expertCondition.isPriorityOperation() && expertCondition.isPriorityCapital()) {
            key = CreateRedisKey.getTheoryAndCapitalKey(expertCondition.getSubjectType(), expertCondition.isUsedCache());
            expert = getExpertByCondition(key, expertCondition);
            if(expert != null){
                return expert;
            }
            key = CreateRedisKey.getTheoryAndOutCapitalKey(expertCondition.getSubjectType(), expertCondition.isUsedCache());
            expert = getExpertByCondition(key, expertCondition);
            if(expert != null){
                return expert;
            }
            key = CreateRedisKey.getOperationAndCapitalKey(expertCondition.getSubjectType(), expertCondition.isUsedCache());
            expert = getExpertByCondition(key, expertCondition);
            if(expert != null){
                return expert;
            }
            key = CreateRedisKey.getOperationAndOutCapitalKey(expertCondition.getSubjectType(), expertCondition.isUsedCache());
            expert = getExpertByCondition(key, expertCondition);
            return expert;
        } else {
            key = CreateRedisKey.getTheoryAndOutCapitalKey(expertCondition.getSubjectType(), expertCondition.isUsedCache());
            expert = getExpertByCondition(key, expertCondition);
            if(expert != null){
                return expert;
            }
            key = CreateRedisKey.getTheoryAndCapitalKey(expertCondition.getSubjectType(), expertCondition.isUsedCache());
            expert = getExpertByCondition(key, expertCondition);
            if(expert != null){
                return expert;
            }
            key = CreateRedisKey.getOperationAndOutCapitalKey(expertCondition.getSubjectType(), expertCondition.isUsedCache());
            expert = getExpertByCondition(key, expertCondition);
            if(expert != null){
                return expert;
            }
            key = CreateRedisKey.getOperationAndCapitalKey(expertCondition.getSubjectType(), expertCondition.isUsedCache());
            expert = getExpertByCondition(key, expertCondition);
            return expert;
        }
    }


    /**
     * 1)从未分配的缓存中获取专家,优先满足一个实务专家,同一组专家所在单位不同，其次再区别京内与京外专家
     * 2) 根据operation与capital的取值优先进行查询判断
     * @param subjectType
     * @param operation
     * @param capital
     * @param isAssigned
     * @param workload
     * @return
     */
    private String getExpertBySubjectTypeAndWorkload(String subjectType, boolean operation, boolean capital, boolean isAssigned, int workload){
        String key;
        if(operation == true &&  capital == true) {
            key = CreateRedisKey.getOperationAndCapitalKey(subjectType, isAssigned);
            if(!isExistedExpert(key,isAssigned,workload)) {
                key = CreateRedisKey.getOperationAndOutCapitalKey(subjectType, isAssigned);
            } else {
                return key;
            }
            if(!isExistedExpert(key,isAssigned,workload)) {
                key = CreateRedisKey.getTheoryAndCapitalKey(subjectType, isAssigned);
            } else {
                return key;
            }
            if(!isExistedExpert(key,isAssigned,workload)) {
                key = CreateRedisKey.getTheoryAndOutCapitalKey(subjectType, isAssigned);
            } else {
                return key;
            }
            if(!isExistedExpert(key,isAssigned,workload)) {
                return null;
            }
        }else if(operation == true &&  capital == false) {
            key = CreateRedisKey.getOperationAndOutCapitalKey(subjectType, isAssigned);
            if(!isExistedExpert(key,isAssigned,workload)) {
                key = CreateRedisKey.getOperationAndCapitalKey(subjectType, isAssigned);
            } else {
                return key;
            }
            if(!isExistedExpert(key,isAssigned,workload)) {
                key = CreateRedisKey.getTheoryAndOutCapitalKey(subjectType, isAssigned);
            } else {
                return key;
            }
            if(!isExistedExpert(key,isAssigned,workload)) {
                key = CreateRedisKey.getTheoryAndCapitalKey(subjectType, isAssigned);
            } else {
                return key;
            }
            if(!isExistedExpert(key,isAssigned,workload)) {
                return null;
            }
        }else if(operation == false && capital == true) {
            key = CreateRedisKey.getTheoryAndCapitalKey(subjectType, isAssigned);
            if(!isExistedExpert(key,isAssigned,workload)) {
                key = CreateRedisKey.getTheoryAndOutCapitalKey(subjectType, isAssigned);
            } else {
                return key;
            }
            if(!isExistedExpert(key,isAssigned,workload)) {
                key = CreateRedisKey.getOperationAndCapitalKey(subjectType, isAssigned);
            } else {
                return key;
            }
            if(!isExistedExpert(key,isAssigned,workload)) {
                key = CreateRedisKey.getOperationAndOutCapitalKey(subjectType, isAssigned);
            } else {
                return key;
            }
            if(!isExistedExpert(key,isAssigned,workload)) {
                return null;
            }
        } else {
            key = CreateRedisKey.getTheoryAndOutCapitalKey(subjectType, isAssigned);
            if(!isExistedExpert(key,isAssigned,workload)) {
                key = CreateRedisKey.getTheoryAndCapitalKey(subjectType, isAssigned);
            } else {
                return key;
            }
            if(!isExistedExpert(key,isAssigned,workload)) {
                key = CreateRedisKey.getOperationAndOutCapitalKey(subjectType, isAssigned);
            } else {
                return key;
            }
            if(!isExistedExpert(key,isAssigned,workload)) {
                key = CreateRedisKey.getOperationAndCapitalKey(subjectType, isAssigned);
            } else {
                return key;
            }
            if(!isExistedExpert(key,isAssigned,workload)) {
                return null;
            }
        }
        return key;
    }

    /**
     * 应该从两方面进行判断：
     * 1. 工作量是否达标；
     * 2. 是否属于同一组单位；
     * @param expertCondition
     * @return
     */
    private Expert getExpertByCondition(final String key, final ExpertCondition expertCondition){
        Set<Object> expertIds = redisService.sGet(key);
        if(expertIds == null || expertIds.size() < 1){
            LOG.error("不存在该专家：" + key);
            return null;
        }

        List<Expert> existExperts = expertCondition.getExperts();
        List<Expert> candidates = new ArrayList();
        for(Object one:expertIds) {
            String expertId = (String)one;
            Expert expert = (Expert) redisService.get(CreateRedisKey.createExpertIDKeys(expertId));
            if(expert.getWorkload() < expertCondition.getWorkload()){
                LOG.error("专家的工作量不满足条件：expertId =" + expertId);
                continue;
            }

            if(existExperts != null && existExperts.size() > 0){
                boolean sameCompany = false;
                for(Expert existOne:existExperts) {
                    if(existOne.getCompany().equals(expert.getCompany())){
                        sameCompany = true;
                        LOG.error("该专家与已选择的专家在同一单位：expertId =" + expertId);
                        break;
                    }
                }
                if(!sameCompany){
                    candidates.add(expert);
                }
            } else {
                candidates.add(expert);
            }
        }

        if(candidates.size() < 1){
            LOG.error("为找到满足条件的专家！");
            return null;
        }
        Random random = new Random();
        int n = random.nextInt(candidates.size());
        return candidates.get(n);
    }

    /**
     * 应该从两方面进行判断：
     * 1. 工作量是否达标；
     * 2. 是否属于同一组单位；
     * @param key
     * @param isAssigned
     * @param workload
     * @return
     */
    private boolean isExistedExpert(String key, boolean isAssigned, int workload){
        if(isAssigned){
            Set<Object> expertIds = redisService.sGet(key);
            for(Object one:expertIds){
                String expertId = (String)one;
                Expert expert = (Expert) redisService.get(CreateRedisKey.createExpertIDKeys(expertId));
                if(expert.getWorkload() >= workload){
                    return true;
                }
            }
            return false;
        } else {
            return redisService.sGetSetSize(key) > 0;
        }
    }


    public boolean run(Long planId, List<ITopic> topics){
        boolean succeed = lock.tryLock();
        if(succeed){
            autoAssignExpert(planId, topics);
            lock.unlock();
            return true;
        } else {
            return false;
        }
    }
}
